﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CSA.Lib;

namespace CSA.Operator
{
    public class WeightBasedProcessor : CSMOProcessor
    {
        #region Fields

        CSPopulation m_OperatePopulation = null;
        String m_CurUsedFunctionName = "";
        Hashtable m_FunctionNames = new Hashtable();

        #endregion

        #region Properties

        public String Name
        {
            get { return "WeightBasedProcessor"; }
        }

        public String Caption
        {
            get { return global::CSA.Operator.TextString.MultiObjectiveProcessingOperatorCaption; }
        }

        public String Description
        {
            get { return global::CSA.Operator.TextString.MultiObjectiveProcessingOperator; }
        }

        public String Library
        {
            get { return "CSA.Operator"; }
        }

        public Hashtable Get_Parameters(String nFunctionName)
        {
            String nValidateName = "";
            if (nFunctionName.Trim() == "" || !m_FunctionNames.Contains(nFunctionName))
            {
                nValidateName = "DefaultMO";

            }
            else
            {
                nValidateName = nFunctionName;
            }
            CSFuntionInfo nDefulatParas = (CSFuntionInfo)m_FunctionNames[nValidateName];
            return nDefulatParas.Parameters;
        }       

        public Hashtable FunctionNames
        {
            get { return m_FunctionNames; }
        }

        public string MethodName
        {
            get { return m_CurUsedFunctionName; }
            set { m_CurUsedFunctionName = value; }
        }

        public bool WeightBased
        {
            get { return true; }
        }

        #endregion

        #region Methods

        public WeightBasedProcessor()
        {           
        }

        public bool Execute(CSPopulation nOperatePopulation, ref String nErrorStr)
        {
            m_OperatePopulation = nOperatePopulation;
            if (m_CurUsedFunctionName.Trim() == "" || !m_FunctionNames.Contains(m_CurUsedFunctionName))
            {
                m_CurUsedFunctionName = "DefaultMO";
            }     
            if (m_CurUsedFunctionName == "DefaultMO")
            {
                return MOFixedWeight(ref nErrorStr);
            }         
            return true;
        }


        private bool MOFixedWeight(ref String nErrorStr)
        {
            try
            {
                //Read Weight
                CSFuntionInfo nDefulatParas = (CSFuntionInfo)m_FunctionNames[m_CurUsedFunctionName];
                Hashtable nParas = nDefulatParas.Parameters;
                ICSOptimizationProblem nProblem = m_OperatePopulation.ProblemInfo;
                for (int i = 0; i < nProblem.Objectives.Count; i++)
                {
                    CSParameter nCurPara = (CSParameter)nParas[nProblem.Objectives[i].Name];
                    nProblem.Objectives[i].Weight = (float)Convert.ToDecimal(nCurPara.Value.ToString());
                }
                m_OperatePopulation.StatisticPopulationObjectiveValues();
                List<CSAntibody> nPop = m_OperatePopulation.NewAntibodies;
                bool succes1 = MOFixedWeight(m_OperatePopulation.NewAntibodies, ref nErrorStr);
                bool succes2 = MOFixedWeight(m_OperatePopulation.MemoryAntibodies, ref nErrorStr);
                bool succes3 = MOFixedWeight(m_OperatePopulation.Antibodies, ref nErrorStr);
                return succes1 && succes2 && succes3;
            }
            catch (Exception ex)
            {
                nErrorStr = ex.Message;
                return false;
            }
        }
   
        private bool MOFixedWeight(List<CSAntibody> nPop,ref String nErrorStr)
        {
            try
            {
                ICSOptimizationProblem nProblem = m_OperatePopulation.ProblemInfo;              
                for (int nCurAb = 0; nCurAb < nPop.Count; nCurAb++)
                {
                    nPop[nCurAb].Affinity = 0.0;
                }
                //Normalize the objective values       
                List<AI.Core.DataStatisticResult> nObjectiveStatistics = m_OperatePopulation.ObjectiveStatistic;
                for (int curObj = 0; curObj < nProblem.Objectives.Count; ++curObj)
                {
                    CSObjectiveInfo nCurObjectiveInfo = nProblem.Objectives[curObj];
                    AI.Core.DataStatisticResult nCurObjectiveStatistic = nObjectiveStatistics[curObj];
                    double nObjectiveValueRange = nCurObjectiveStatistic.Maximum - nCurObjectiveStatistic.Minimum;
                    if (nCurObjectiveInfo.IsCostObjecitve)
                    {
                        for (int i = 0; i < nPop.Count; i++)
                        {
                            CSAntibody nCurAntibody = nPop[i];
                            double nCurObjValue = nCurAntibody.ObjectiveValues[curObj];
                            if (nObjectiveValueRange == 0)
                            {
                                nCurAntibody.Affinity += nCurObjectiveInfo.Weight * 1;
                            }
                            else
                            {
                                nCurAntibody.Affinity += nCurObjectiveInfo.Weight * ((nCurObjectiveStatistic.Maximum - nCurObjValue) / nObjectiveValueRange);
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < nPop.Count; i++)
                        {
                            CSAntibody nCurAntibody = nPop[i];
                            double nCurObjValue = nCurAntibody.ObjectiveValues[curObj];
                            if (nObjectiveValueRange == 0)
                            {
                                nCurAntibody.Affinity += nCurObjectiveInfo.Weight * 1;
                            }
                            else
                            {
                                nCurAntibody.Affinity += nCurObjectiveInfo.Weight * ((nCurObjValue - nCurObjectiveStatistic.Minimum) / nObjectiveValueRange);
                            }
                        }
                    }
                }
                nPop.Sort(new AntibodyCompare());
                return true;
            }
            catch (Exception ex)
            {
                nErrorStr = ex.Message;
                return false;
            }
        } 

        public void InitialParameters(ICSOptimizationProblem nMOProblem)
        {
            m_FunctionNames.Clear();        
            CSFuntionInfo nFixedWeight = new CSFuntionInfo();
            nFixedWeight.Caption = global::CSA.Operator.TextString.FixedWeightCaption;
            nFixedWeight.Description = global::CSA.Operator.TextString.FixedWeightDes;
            nFixedWeight.Name = "DefaultMO";
            if (nMOProblem != null)
            {
                Hashtable nFunctionParas = new Hashtable();
                for (int i = 0; i < nMOProblem.Objectives.Count;i++ )
                {
                    CSParameter nObjectiveWeight = new CSParameter();
                    nObjectiveWeight.Type = ParameterType.enumFloat;
                    nObjectiveWeight.Caption = nMOProblem.Objectives[i].Caption;
                    nObjectiveWeight.Description = "The weight of " + nMOProblem.Objectives[i].Caption;
                    nObjectiveWeight.Name = nMOProblem.Objectives[i].Name;
                    nObjectiveWeight.Value = 0.05;
                    nObjectiveWeight.DomainType = enumParasDomain.enumDomainExtent;
                    string low1 = "0.01";
                    string up1 = "1.0";
                    List<string> nDomains1 = new List<string>();
                    nDomains1.Add(low1);
                    nDomains1.Add(up1);
                    nObjectiveWeight.DomainValues = nDomains1;
                    nFunctionParas.Add(nMOProblem.Objectives[i].Name, nObjectiveWeight);
                }
                nFixedWeight.Parameters = nFunctionParas;
            }
            m_FunctionNames.Add(nFixedWeight.Name, nFixedWeight);
        }

        #endregion
    }
}
